from ..attributes import *
from ..attributes import _

from .rendering import *


class Element(Object):
    primitive        = Attribute(initiable = False)    
    fixed_classes    = SetAttribute(initiable = False)
    class_conditions = DictAttribute(initiable = False, writable = True)
    
    element_function =_ (None)
    
    @property
    def children(self):
        return []
    
    @property
    def is_data(self):
        return False
    
    @property
    def has_primitive(self):
        return self.primitive is not None
    
    def add_class(self, name):
        self._fixed_classes.add(name)
        
        for child in self.children:
            child.add_class(name)
    
    def add_classes(self, *names):
        self._fixed_classes |= set(names)
        
        for child in self.children:
            child.add_classes(*names)
    
    @property
    def dynamic_classes(self):
        return set(cls for cls, condition in self.class_conditions.items() if condition())
    
    @property
    def classes(self):
        return self.fixed_classes | self.dynamic_classes
    
    def bind(self, information):
        self.bind_sources(information.information)
        self.bind_classes(information.classes)
    
    def bind_sources(self, sources):
        for child in self.children:
            child.bind_sources(sources)
    
    def bind_classes(self, classes):
        for child in self.children:
            child.bind_classes(classes)
        
    def create_elements_for(self, primitives):
        if self.element_function is not None:
            self.primitive = getattr(primitives, self.element_function)(self)
        
        for child in self.children:
            child.create_elements_for(primitives)
    
    def set_area(self, area):
        if self.has_primitive:
            self.primitive.set_area(area)
        
        self.layout_in(area)
    
    def layout_in(self, area):
        pass
    
    @property
    def intrinsic_size(self):
        return self.primitive.intrinsic_size
    
    def destroy(self):
        if self.has_primitive:
            self.primitive.destroy()
        
        for child in self.children:
            child.destroy()


class Container(Element):
    children = ListAttribute()
    
    def add_child(self, child):
        self._children.append(child)
